#include "thread.h"
#include "service.h"

DWORD WINAPI threadProcess(void* ctx);

Thread::~Thread() {}

void Thread::start() {
	handle_ = CreateThread(NULL, 0, threadProcess, this, 0, &threadId_);
}

bool Thread::join() {
	int32 ret = WaitForSingleObjectEx(handle_, INFINITE, 1);
	if (WAIT_OBJECT_0 == ret)
	{
		return true;
	}
	return false;
}

bool Thread::addService(Service* s) {
	shengine_assert(s);
	lock_.lock();
	ServiceMap::iterator itr = serviceCacheMap_.find(s->getHandle());
	if (itr == serviceCacheMap_.end()) {
		serviceCacheMap_.insert(std::make_pair(s->getHandle(), s));
		s->onAllocThread(this);
		lock_.unlock();
		return true;
	}
	else {
		shengine_assert(0);
		delete s;
		lock_.unlock();
		return false;
	}
}

bool Thread::removeService(const Guid64& handle) {
	ServiceMap::iterator itr = serviceMap_.find(handle);
	if (itr != serviceMap_.end()) {
		itr->second->onRemoveFromThread();
		serviceMap_.erase(handle);
		return true;
	}
	else {
		lock_.lock();
		itr = serviceCacheMap_.find(handle);
		if (itr != serviceCacheMap_.end()) {
			serviceCacheMap_.erase(handle);
			lock_.unlock();
			return true;
		}
		lock_.unlock();
	}
	return false;
}

void Thread::checkNewService() {
	lock_.lock();
	if (!serviceCacheMap_.empty()) {
		ServiceMap::iterator itr = serviceCacheMap_.begin();
		for (; itr != serviceCacheMap_.end(); ++itr) {
			serviceMap_.insert(std::make_pair(itr->first, itr->second));
		}
		serviceCacheMap_.clear();
	}
	lock_.unlock();
}

void Thread::checkThreadState() {
	 if (state_ == THREAD_STATE_INIT) {
		prepare();
		state_ = THREAD_STATE_READIED;
	}
	else if (state_ == THREAD_STATE_TOPAUSE) {
		state_ = THREAD_STATE_PAUSE;
	}
	else if (state_ == THREAD_STATE_TOEXIT) {
		state_ = THREAD_STATE_EXIT;
	}
}

bool Thread::runFrame() {
	checkThreadState();
	checkNewService();

	bool isRunning = (state_ != THREAD_STATE_INIT && state_ != THREAD_STATE_PAUSE);
	ServiceMap::iterator itr = serviceMap_.begin();
	for (; itr != serviceMap_.end();) {
		Service* s = itr->second;
		if (!s->isExit()) {
			s->processBase();
			if (isRunning) {
				s->process();
			}
			++itr;
		}
		else {
			printf("Log: Service[%s] handle[%llu] exit !\n", s->getName().c_str(), s->getHandle().getValue());
			s->onRemoveFromThread();
			itr = serviceMap_.erase(itr);
		}
	}
	
	return state_ != THREAD_STATE_EXIT;
}

DWORD WINAPI threadProcess(void* ctx) {
	shengine_assert(ctx);
	Thread* thread = (Thread*)ctx;
	while (thread->runFrame())
	{
		Sleep(4);
	}
	thread->join();
	return 0;
}
